package com.qsl;

import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.activation.URLDataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Properties;

public class MailTest {

    private static final String OSS_FILE_URL = "";

    private static final String MAIL_HOST = "smtp.gildata.com";
    private static final String MAIL_PROTOCOL = "smtp";
    private static final String MAIL_USER_NAME = "app_public@gildata.com";
    private static final String MAIL_AUTH_CODE = "Hello@12345";        // 换成正确的授权码

    // private static final String MAIL_TO = "youzb45615@hundsun.com";
    // private static final String MAIL_TO = "youzb@gildata.com";
    private static final String MAIL_TO = "997914490@qq.com";

    public static void main(String[] args) throws Exception {
        File file = new File("D:\\产品包2115_20231221.zip");
        List<File> attachments = new ArrayList<>();
        attachments.add(new File("D:/下载/mysql-8.0.25-winx64.zip"));
//        // 源文件（可以是多个）进行分卷压缩
//        List<File> fileList = splitVolumeCompressFiles(20, attachments, "D:/volume", "mysql-8.0.25-winx64");
//        // 多封邮件进行发送，一封一个附件
//        for (int i=0; i<fileList.size(); i++) {
//            // 可以异步发送
//            sendMailNick("邮件正文", MAIL_TO, Arrays.asList(fileList.get(i)), "大文件，分卷压缩(" + (i+1) + "/" + fileList.size() + ")");
//        }
        sendEmail465("附件大小测试", MAIL_TO, file);
    }

    /**
     * 使用加密的方式,利用465端口进行传输邮件,开启ssl
     * @param message    发送的消息
     * @param to    为收件人邮箱
     */
    public static void sendEmailUrl(String message, String to, URL url, String fileName) throws Exception {
        //设置邮件会话参数
        Properties props = new Properties();
        //邮箱的发送服务器地址
        props.setProperty("mail.smtp.host", MAIL_HOST);
        props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.setProperty("mail.smtp.socketFactory.fallback", "false");
        props.put("mail.smtp.ssl.enable", "true");

        //邮箱发送服务器端口,这里设置为465端口
        props.setProperty("mail.smtp.port", "465");
        props.setProperty("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.auth", "true");

        //获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm
        Session session = Session.getDefaultInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(MAIL_USER_NAME, MAIL_AUTH_CODE);
            }
        });

        // 开启调试
        session.setDebug(true);

        Multipart multipart = new MimeMultipart();
        BodyPart contentPart = new MimeBodyPart();
        contentPart.setContent(message, "text/html;charset=UTF-8");
        multipart.addBodyPart(contentPart);

        if (url != null) {
            BodyPart attachmentBodyPart = new MimeBodyPart();
            DataSource dataSource= new URLDataSource(url);
            attachmentBodyPart.setDataHandler(new DataHandler(dataSource));
            attachmentBodyPart.setFileName(MimeUtility.encodeWord(fileName));
            multipart.addBodyPart(attachmentBodyPart);
        }

        //通过会话,得到一个邮件,用于发送
        Message msg = new MimeMessage(session);
        //设置发件人
        msg.setFrom(new InternetAddress(MAIL_USER_NAME));
        //设置收件人,to为收件人,cc为抄送,bcc为密送
        msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));
        // msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(to, false));
        // msg.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(to, false));
        msg.setSubject("发送网络文件测试");
        //设置邮件消息
        msg.setContent(multipart);
        //设置发送的日期
        msg.setSentDate(new Date());

        //调用Transport的send方法去发送邮件
        Transport.send(msg);
    }

    /**
     * 使用加密的方式,利用465端口进行传输邮件,开启ssl
     * @param message    发送的消息
     * @param to    为收件人邮箱
     */
    public static void sendEmail465(String message, String to, File attachment) throws Exception {
        //System.setProperty("mail.mime.splitlongparameters","false");
        //设置邮件会话参数
        Properties props = new Properties();
        //邮箱的发送服务器地址
        props.setProperty("mail.smtp.host", MAIL_HOST);
        props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.setProperty("mail.smtp.socketFactory.fallback", "false");
        props.put("mail.smtp.ssl.enable", "true");

        //邮箱发送服务器端口,这里设置为465端口
        props.setProperty("mail.smtp.port", "465");
        props.setProperty("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.auth", "true");

        //获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm
        Session session = Session.getDefaultInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(MAIL_USER_NAME, MAIL_AUTH_CODE);
            }
        });

        // 开启调试
        session.setDebug(false);

        Multipart multipart = new MimeMultipart();
        BodyPart contentPart = new MimeBodyPart();
        //contentPart.setContent(message, "text/html;charset=UTF-8");
        contentPart.setText(message);
        multipart.addBodyPart(contentPart);

        if (attachment != null) {
            BodyPart attachmentBodyPart = new MimeBodyPart();
            DataSource source = new FileDataSource(attachment);
            attachmentBodyPart.setDataHandler(new DataHandler(source));
            //MimeUtility.encodeWord可以避免文件名乱码
            attachmentBodyPart.setFileName(MimeUtility.encodeWord(attachment.getName()));
            multipart.addBodyPart(attachmentBodyPart);
        }

        //通过会话,得到一个邮件,用于发送
        Message msg = new MimeMessage(session);
        //设置发件人
        msg.setFrom(new InternetAddress(MAIL_USER_NAME));
        //设置收件人,to为收件人,cc为抄送,bcc为密送
        msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));
        // msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(to, false));
        // msg.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(to, false));
        msg.setSubject("我是主题");
        //设置邮件消息
        msg.setContent(multipart);
        //设置发送的日期
        msg.setSentDate(new Date());

        //调用Transport的send方法去发送邮件
        Transport.send(msg);
    }

    /**
     * 默认端口25
     * @param content
     * @param to
     * @param attachment 附件
     * @throws MessagingException
     */
    public static void sendMail25(String content, String to, File attachment) throws Exception {
        // 设置发件相关信息
        Properties prop = new Properties();
        prop.setProperty("mail.host", MAIL_HOST);
        prop.setProperty("mail.transport.protocol", MAIL_PROTOCOL);
        prop.setProperty("mail.smtp.auth", "true");

        // 创建发件会话
        Session session = Session.getInstance(prop);
        session.setDebug(true);

        // 创建传输对象
        Transport trans = session.getTransport();
        trans.connect(MAIL_HOST, MAIL_USER_NAME, MAIL_AUTH_CODE);

        Multipart multipart = new MimeMultipart();
        BodyPart contentPart = new MimeBodyPart();
        contentPart.setContent(content, "text/html;charset=UTF-8");
        multipart.addBodyPart(contentPart);

        if (attachment != null) {
            BodyPart attachmentBodyPart = new MimeBodyPart();
            DataSource source = new FileDataSource(attachment);
            attachmentBodyPart.setDataHandler(new DataHandler(source));

            // 网上流传的解决文件名乱码的方法，其实用MimeUtility.encodeWord就可以很方便的搞定
            // 这里很重要，通过下面的Base64编码的转换可以保证你的中文附件标题名在发送时不会变成乱码
            //sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
            //messageBodyPart.setFileName("=?GBK?B?" + enc.encode(attachment.getName().getBytes()) + "?=");

            //MimeUtility.encodeWord可以避免文件名乱码
            attachmentBodyPart.setFileName(MimeUtility.encodeWord(attachment.getName()));
            multipart.addBodyPart(attachmentBodyPart);
        }

        // 创建邮件消息对象
        Message message = new MimeMessage(session);
        // 设置发件人信息
        message.setFrom(new InternetAddress(MAIL_USER_NAME));
        // 设置收件人信息
        message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
        // 设置邮件主题和内容信息
        message.setSubject("邮件测试");
        message.setContent(multipart);
        // 发送邮件
        trans.sendMessage(message, message.getAllRecipients());
        // 关闭传输
        trans.close();
    }

    /**
     * 发送邮件，带附件
     * @param content 正文
     * @param to 收件人
     * @param attachments 附件列表
     * @param title 邮件标题
     * @throws Exception
     */
    public static void sendMailNick(String content, String to, List<File> attachments, String title) throws Exception {
        //设置邮件会话参数
        Properties props = new Properties();
        //邮箱的发送服务器地址
        props.setProperty("mail.smtp.host", MAIL_HOST);
        props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.setProperty("mail.smtp.socketFactory.fallback", "false");
        props.put("mail.smtp.ssl.enable", "true");

        //邮箱发送服务器端口,这里设置为465端口
        props.setProperty("mail.smtp.port", "465");
        props.setProperty("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.auth", "true");

        //获取到邮箱会话,利用匿名内部类的方式,将发送者邮箱用户名和密码授权给jvm
        Session session = Session.getDefaultInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(MAIL_USER_NAME, MAIL_AUTH_CODE);
            }
        });
        // 开启调试
        session.setDebug(true);
        // 创建传输对象
        Transport trans = session.getTransport();
        trans.connect(MAIL_HOST, "青石路", MAIL_AUTH_CODE);
        // 创建邮件消息对象
        Message message = new MimeMessage(session);
        // 设置发件人信息（昵称：青石路）
        message.setFrom(new InternetAddress(MAIL_USER_NAME, "青石路", "UTF-8"));
        // 设置收件人信息
        message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
        // 设置正文
        Multipart multipart = new MimeMultipart();
        BodyPart contentPart = new MimeBodyPart();
        contentPart.setContent(content, "text/html;charset=UTF-8");
        multipart.addBodyPart(contentPart);
        // 添加附件
        if (Objects.nonNull(attachments) && !attachments.isEmpty()) {
            for (File e : attachments) {
                BodyPart attachmentBodyPart = new MimeBodyPart();
                DataSource source = new FileDataSource(e);
                attachmentBodyPart.setDataHandler(new DataHandler(source));
                //MimeUtility.encodeWord可以避免文件名乱码
                attachmentBodyPart.setFileName(MimeUtility.encodeWord(e.getName()));
                multipart.addBodyPart(attachmentBodyPart);
            }
        }
        // 设置邮件主题和内容信息
        message.setSubject(title);
        message.setContent(multipart);
        // 发送邮件
        trans.sendMessage(message, message.getAllRecipients());
        // 关闭传输
        trans.close();
    }

    /**
     * 分卷压缩
     * @param sizeThreshold 分卷阈值，即多大进行一次分卷，单位:M
     * @param sourceFiles 源文件列表
     * @param destDirPath 目标目录，将源文件分卷到哪个目录
     * @param zipFileName 压缩文件名
     * @return 分卷文件列表
     * @throws Exception
     */
    public static List<File> splitVolumeCompressFiles(int sizeThreshold, List<File> sourceFiles, String destDirPath, String zipFileName) throws Exception {
        List<File> zipFiles = new ArrayList<>();
        if (Objects.isNull(sourceFiles) && sourceFiles.isEmpty()) {
            return zipFiles;
        }
        // 目录不存在则创建
        File dir = new File(destDirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try (ZipFile zipFile = new ZipFile(destDirPath + File.separator + zipFileName + ".zip")) {
            ZipParameters parameters = new ZipParameters();
            parameters.setCompressionMethod(CompressionMethod.DEFLATE);
            parameters.setCompressionLevel(CompressionLevel.NORMAL);
            zipFile.createSplitZipFile(sourceFiles, parameters, true, sizeThreshold * 1024L * 1024L);
            List<File> splitZipFiles = zipFile.getSplitZipFiles();
            if (Objects.nonNull(splitZipFiles) && !splitZipFiles.isEmpty()) {
                zipFiles = splitZipFiles;
            }
        }
        return zipFiles;
    }

    public static void strLength() throws Exception{
        System.setProperty("mail.mime.splitlongparameters","false");
        //System.setProperty("mail.mime.charset","UTF-8");
        String s = MimeUtility.encodeWord("中行关联方股票调出_20221215.xlsx");
        String decodeWord = MimeUtility.decodeWord(s);
        System.out.println(s);
        System.out.println(decodeWord);
    }
}
